using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[AddComponentMenu("Scripts/Ship Control/Bullets Control/Spark Bullets")]
public class csSparkBulletCtrl : csBulletAttributes 
{
#region Define
//Type	
	[System.Serializable]
	public enum EXPLOSION_TYPE
	{
		EXPLOSION_BY_TIME = 0,
		EXPLOSION_BY_LEN,
	}	
	
	protected enum STATUS_TYPE
	{
		STATUS_NONE		= 0,	//Do nothing
		STATUS_COUNTDOWN,		//Count Down
		STATUS_EXPLOSION,		//Explosion
	}
	
//Function pointer
	protected delegate void FUNC_Status();
	

//Constant
	public const int EXPLOSION_DELAY_TIME 	= 80;		//Unit: Frames
	public const int EXPLOSION_DELAY_LEN	= 100;		//Unit: Pixels		
	public const int DEFAULT_BULLETS_NUM	= 4;	
	
	public const int EXPLOSION_COUNTDOWN_BLING_DELAY_TIME	= 1;	//Unit: Frames
	public const int EXPLOSION_COUNTDOWN_BLING_START_TIME	= 30;	//The start to show bling time.
#endregion		
	
#region InputData
//------------ Model setting -------------
	public string		DeathZoneName;			//Because of the Death Zones are arround the scene.
	public string		TargetBulletTagName;	//For destroy target's bullet using.
	public string		TargetTagName;			//The target tag name.
	
//------------ Working Setting -----------	
	public bool				ControlBySelf 						= false;								//Self control flag
	public int				BulletsNumber						= DEFAULT_BULLETS_NUM;					//Amount of bullets	
	public EXPLOSION_TYPE	ExplosionType						= EXPLOSION_TYPE.EXPLOSION_BY_TIME;		//Explore Type	
	public int				ExplosionDelayValue					= EXPLOSION_DELAY_TIME;					//Explore delay value
	public int				ExplosionCountDownBlingStartFrame	= EXPLOSION_COUNTDOWN_BLING_START_TIME;	//The start frame to show bling time.
	public int				ExplosionCountDownBlingDelayValue	= EXPLOSION_COUNTDOWN_BLING_DELAY_TIME;	//Explosion countdown delay value
	public float			MovingSpeed							= 1.0f;									//Unit: Pixel, Update per frame		
	public Vector3			ShotDirect;																	//Shot Directoin	
#endregion
	
#region DataMember
//----------- Bullets ---------------
	protected uint		mExplosionDelayCounter		= 0;		//Delay counter	
	protected Vector3	mPreBulletPos;							//Previous position of bullet
	protected uint		mExplosionCountdownBlingCounter	= 0;	//Bling counter for explosion countdown
	
//Status
	protected STATUS_TYPE mStatus = STATUS_TYPE.STATUS_NONE;
	
//Status function list	
	protected Dictionary<STATUS_TYPE, FUNC_Status> mSparkStatusFuncList = new Dictionary<STATUS_TYPE, FUNC_Status>();	
	
//----------- Common ----------------
	protected uint mFrameCounter = 0;
#endregion
	
#region MemeberFunc
//Moving	
	public void OnMove()
	{
		if(this.mSparkStatusFuncList[this.mStatus] == null)
			return;
		
		this.mSparkStatusFuncList[this.mStatus]();
	}
	
//Control for parent - Num = The amount of bullets, InitPos = The inital position.
//	For AddComponent using
	public void Shoot(int Num , Vector3 ShotDirect, EXPLOSION_TYPE Type, int DelayVal, float MovingSpeed) {
		this.GenerateBullet(Num , ShotDirect, Type, DelayVal, MovingSpeed);
	}
	
// For Attached Component using
	public void Shoot(){
		this.ExplosionDelayValue = Random.Range(0, EXPLOSION_DELAY_TIME);
		if(this.ExplosionDelayValue < 30)
			this.ShotDirect = Vector3.up;
		
		this.mStatus = STATUS_TYPE.STATUS_COUNTDOWN;
	}
	
//For Player using	
	public void Shoot(int Num , Vector3 ShotDirect){
		this.GenerateBullet(Num , ShotDirect, this.ExplosionType, this.ExplosionDelayValue, this.MovingSpeed);
	}

	protected void GenerateBullet(int Num , Vector3 ShotDirect, EXPLOSION_TYPE Type, int DelayVal, float MovingSpeed) 
	{
		this.ExplosionType			= Type;
		this.ExplosionDelayValue	= DelayVal;
		this.BulletsNumber			= Num;
		this.ShotDirect				= ShotDirect;
		this.MovingSpeed			= MovingSpeed;
		this.mStatus				= STATUS_TYPE.STATUS_COUNTDOWN;
	}
	
//Destroy - this can inherit from csBulletCtrl
	protected void OnDestroy()
	{
		Destroy(this.gameObject);
	}
	
//Spark generator - Num = the amount of bullet, Angle = the interval of bullet (Unit:deg)
//					The horizontal bullet is not generated in this function.
	protected void GenerateSpark(int Num, Vector3 InitPos, Vector3 ShotDirect, float MovingSpeed)
	{
	//Show sparkle?!
		
	//Calculate the angle
		float Angle = 180.0f / ((float)Num - 1.0f);
			
	//Set the initial angle of original bullet
		Vector3 RotateAngle = this.GetRotateAxisInfo(ShotDirect, 90.0f);		//To horizontal
		this.transform.Rotate(RotateAngle.x, RotateAngle.y, RotateAngle.z);
			
	//Generate new Bullets - including the horizontal
		for(int i = 1 ; i <= Num ; i++ ) 
		{
			Vector3 Pos = new Vector3(this.transform.position.x,
			                          this.transform.position.y + this.transform.localScale.y * this.ShotDirect.y,
			                          this.transform.position.z);
			GameObject bullet = Instantiate(this.gameObject, Pos, this.transform.rotation) as GameObject;
			csBulletCtrl BulletCtrl = bullet.GetComponent<csBulletCtrl>();
			BulletCtrl.FlySpeed = this.MovingSpeed;
			this.transform.Rotate(0.0f, 0.0f, Angle);			
		}
	
	//Destroy original bullet
		Destroy(this.gameObject);
	}
	
//Get rotate axis info by Move direct		
//NOTE: The 90.0f is the offset angle for setting the starting point.
	protected Vector3 GetRotateAxisInfo(Vector3 ShotDirect, float StartedOffsetAngle)
	{
		Vector3 RotateAxisInfo;
		if(ShotDirect == Vector3.up)		//Shot forward
		{
			RotateAxisInfo = new Vector3(0.0f, 0.0f, -90.0f);
		}else if (ShotDirect == Vector3.down){		//Shot backward
			RotateAxisInfo = new Vector3(0.0f, 0.0f, 90.0f);
		}else if (ShotDirect == Vector3.forward){
			RotateAxisInfo = new Vector3(-90.0f, 0.0f, 0.0f);
		}else if (ShotDirect == Vector3.back){
			RotateAxisInfo = new Vector3(90.0f, 0.0f, 0.0f);
		}else if (ShotDirect == Vector3.right){
			RotateAxisInfo = new Vector3(0.0f, 0.0f, -180.0f);
		}else if (ShotDirect == Vector3.left){
			RotateAxisInfo = new Vector3(0.0f, 0.0f, 0.0f);
		}else{
			RotateAxisInfo = new Vector3(0.0f, 0.0f, -90.0f);
		}
		
		return RotateAxisInfo;
	}
	
//-------------- Status Function --------------
//Countdown
	protected void Status_CountDown()
	{
		switch(this.ExplosionType)
		{
			case EXPLOSION_TYPE.EXPLOSION_BY_LEN:
			{
				if( Vector3.Distance(this.transform.position, this.mPreBulletPos) >= this.ExplosionDelayValue)
				{
					this.mStatus = csSparkBulletCtrl.STATUS_TYPE.STATUS_EXPLOSION;		
				}else{
					this.mPreBulletPos = this.transform.position;
				}
			}
			break;
			case EXPLOSION_TYPE.EXPLOSION_BY_TIME:
			{
				if(this.mExplosionDelayCounter++ >= this.ExplosionDelayValue) {
					this.mStatus = csSparkBulletCtrl.STATUS_TYPE.STATUS_EXPLOSION;
					this.mExplosionDelayCounter = 0;
				}
			}
			break;
		}
		
	//Show countdown bling
		if( this.ExplosionDelayValue - this.mExplosionDelayCounter < ExplosionCountDownBlingStartFrame )
		{
			if(this.mExplosionCountdownBlingCounter++ % this.ExplosionCountDownBlingDelayValue == 0)
				this.renderer.enabled = !this.renderer.enabled;
		}
	}
	
//Explosion
	protected void Status_Explosion()
	{
		this.renderer.enabled = true;
		this.GenerateSpark(this.BulletsNumber, this.transform.position, this.ShotDirect, this.MovingSpeed);
		this.mStatus = csSparkBulletCtrl.STATUS_TYPE.STATUS_NONE;
	}
#endregion
	
#region SystemFunc
// Use this for initialization
	void Start () 
	{
//Build the spark status list
		this.mSparkStatusFuncList[STATUS_TYPE.STATUS_NONE] 		= null;
		this.mSparkStatusFuncList[STATUS_TYPE.STATUS_COUNTDOWN]	= new csSparkBulletCtrl.FUNC_Status(this.Status_CountDown);
		this.mSparkStatusFuncList[STATUS_TYPE.STATUS_EXPLOSION]	= new csSparkBulletCtrl.FUNC_Status(this.Status_Explosion);
	}
	
// Update is called once per frame
	void Update () 
	{	
	//Self update controller
		if(!this.ControlBySelf)
			return;
		
	//Bullet Operating
		this.OnMove();
	}
	
//OnTrigger
	void OnTriggerEnter(Collider Target)
	{
		if(Target.gameObject.tag == this.DeathZoneName )
			Object.Destroy(this.gameObject);
	}
#endregion	
	
#region Properties
	public void EnableSelfCtrl(bool Enable) { this.ControlBySelf = Enable; }
	public void SetBulletNum(int Num)		{ this.BulletsNumber = Num;	}
#endregion
}
